package com.yumeng.framework.runtime;

import com.yumeng.common.auth.BaseAuthHelper;
import com.yumeng.common.runtime.EnvironmentHelper;
import com.yumeng.common.runtime.GlobalVariableHelper;
import com.yumeng.common.runtime.SpringPropAdapter;
import com.yumeng.common.utils.JacksonUtils;
import com.yumeng.config.helper.EnvHelper;
import com.yumeng.config.properties.ProjectProperties;
import com.yumeng.config.properties.YumengAuthProperties;
import com.yumeng.config.properties.YumengProperties;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;
import org.springframework.context.ConfigurableApplicationContext;

import javax.sql.DataSource;

/**
 * @author wxd
 * @date 2024/5/29 上午9:09
 */
@Slf4j
public class ApplicationPrinter {

    /**
     * 打印项目信息
     *
     * @param context
     */
    public static void printApplicationInfo(ConfigurableApplicationContext context) {
        ProjectProperties projProps = context.getBean(ProjectProperties.class);
        YumengProperties ymProps = context.getBean(YumengProperties.class);
        DataSource dataSource = context.getBean(DataSource.class);

        log.info("############################################：项目启动信息");
        log.info("项目名称: {}", projProps.getName());
        log.info("项目描述: {}", projProps.getDescription());
        log.info("项目版本: {}", projProps.getVersion());
        log.info("项目作者: {}", projProps.getAuthor());
        log.info("项目端口: {}", SpringPropAdapter.getPort());
        log.info("项目路径: {}", SpringPropAdapter.getContextPath());
        log.info("APP-ID: {}", SpringPropAdapter.getApplicationId());
        log.info("java版本: {}", projProps.getJavaVersion());
        log.info("springBoot版本: {}", projProps.getSpringBootVersion());
        log.info("mybatisPlus版本: {}", projProps.getMybatisPlusVersion());
        log.info("springDoc版本: {}", projProps.getSpringDocVersion());
        if (enableKnife4j()){
            log.info("knife4j版本: {}", projProps.getKnife4jVersion());
        }

        if (EnvHelper.isDev()){
            log.info("groupId: {}", projProps.getGroupId());
            log.info("artifactId: {}", projProps.getArtifactId());
            log.info("sourceEncoding: {}", projProps.getSourceEncoding());
            log.info("outputEncoding: {}", projProps.getOutputEncoding());
            log.info("baseEnumPackages: {}", ymProps.getBaseEnumPackages());
            log.info("enumPackages: {}", ymProps.getEnumPackages());

            log.info("============================================关键组件============================================");
            log.info("DelegatingFilterProxy: {}", JacksonUtils.toJsonString(context.getBeanNamesForType(DelegatingFilterProxyRegistrationBean.class)));

            printDataSourceInfo(dataSource);
            printSpringSecurityInfo(context);
            printYumengFrameInfo(ymProps, context);
        }

        log.info("配置文件：{}", ymProps.getLastCfgName());
        log.info("当前环境：{}", ymProps.getCurrEnvSysDesc());
        log.info("默认时区：{}", GlobalVariableHelper.getInstance().getRegisterTimeZoneId());
        log.info("认证模式：{}-{}", YumengAuthProperties.YumengBasicProperties.getCurrAuthFrame(), YumengAuthProperties.YumengBasicProperties.getIsFBS() ? "前后端分离" : "普通");
        //TODO 数据库时区与应用时区的一致性判断？
        //log.info("数据库时区：{}", TimeZone.getDefault().getID());

        log.info("project start success.............................................................................");
    }

    /**
     * 打印yumeng框架信息
     *
     */
    private static void printYumengFrameInfo(YumengProperties ymProps, ConfigurableApplicationContext context){
        YumengAuthProperties ymAuthProps = context.getBean(YumengAuthProperties.class);

        // 项目profile
        StringBuffer tip = new StringBuffer();
        tip.append("===============================================================================================\n");
        tip.append("                                                                                  \n");
        tip.append("                              ####项目启动####                                      \n");
        tip.append(" 1.数据库准备\n");
        tip.append(" 2.启动Redis服务（可选操作）\n");
        tip.append(" 3.启动SpringBootAdmin Server（可选操作）\n");
        tip.append(" 4.根据项目需要，修改项目配置，请先查看配置文档\n");
        tip.append(" 5.项目模块说明：\n");
        tip.append("    yumeng-admin：           项目管理模块，监控、日志查看等\n");
        tip.append("    yumeng-business：        业务逻辑模块，结合开发者自己的应用领域，封装一些常用业务类，如：行政区划处理\n");
        tip.append("    yumeng-common：          项目基础模块，工具类、常量、通用类型等\n");
        tip.append("    yumeng-example：         示例业务模块\n");
        tip.append("    yumeng-framework：       项目框架模块，顶层抽象、整合、第三方模块整合\n");
        tip.append("    yumeng-generator：       代码生成模块，基于mybatis-plus代码生成模块\n");
        tip.append("    yumeng-scheduled：       任务调度模块\n");
        tip.append("    yumeng-system：          系统通用业务模块，组织、部门、用户、权限等\n");
        tip.append("    yumeng-ui：              UI界面，封装H5等\n");
        tip.append("    yumeng-webapp：          项目启动模块\n");
        tip.append("                                                                                  \n");
        tip.append(" 如开发中遇到bug及问题，及时沟通：\n");
        tip.append("                                                                                  \n");
        tip.append(String.format("baseUrl:      %s\n", ymProps.getBaseUrl()));
        tip.append(String.format("adminUrl:     %s\n", ymProps.getBaseUrl() + ymProps.getAdminUrl()));
        tip.append(String.format("homeUrl:      %s\n", ymProps.getBaseUrl() + ymProps.getHomeUrl()));

        if (enableKnife4j()){
            tip.append(String.format("knife4jUrl:   %s\n", ymProps.getBaseUrl() + ymProps.getKnife4jUrl()));
        }else{
            tip.append(String.format("springDocUrl: %s\n", ymProps.getBaseUrl() + ymProps.getSpringDocUrl()));
        }

        tip.append(String.format("loginUrl:     %s\n", ymProps.getBaseUrl() + ymAuthProps.getBasic().getLoginUrl()));

        tip.append("===============================================================================================\n");
        log.info(tip.toString());
    }

    private static void printDataSourceInfo(DataSource dataSource){
        log.info("数据库连接池: {}", JacksonUtils.toJsonString(dataSource.getClass().getName()));
        String poolName = "#";
        String maxPoolSize = "#";
        String minIdle = "#";
        String idleTimeout = "#";
        String connectionTimeout = "#";
        String maxLifetime = "#";
        String connectionTestQuery = "#";
        if (dataSource instanceof HikariDataSource ds){
            poolName = ds.getPoolName();
            maxPoolSize = String.valueOf(ds.getMaximumPoolSize());
            minIdle = String.valueOf(ds.getMinimumIdle());
            idleTimeout = String.valueOf(ds.getIdleTimeout());
            connectionTimeout = String.valueOf(ds.getConnectionTimeout());
            maxLifetime = String.valueOf(ds.getMaxLifetime());
            connectionTestQuery = ds.getConnectionTestQuery();
        }
        log.info("--名称: {}", poolName);
        log.info("--最大连接数: {}", maxPoolSize);
        log.info("--最小空闲连接数: {}", minIdle);
        log.info("--空闲后的超时时间（毫秒）: {}", idleTimeout);
        log.info("--最大等待时间（毫秒）: {}", connectionTimeout);
        log.info("--最大生命周期（毫秒）: {}", maxLifetime);
        log.info("--是否可用的SQL: {}", connectionTestQuery);
    }

    /**
     * 打印SpringSecurity信息
     * org.springframework.security.config.BeanIds
     * @param context
     */
    private static void printSpringSecurityInfo(ConfigurableApplicationContext context){
        BaseAuthHelper.printAuthFrameInfo(context);
    }


    /**
     * 是否启用了knife4j
     *
     * @param
     * @return
     */
    private static boolean enableKnife4j(){
        return EnvironmentHelper.containsKey("knife4j.enable");
    }
}
